/*
    全局友元模板函数类内实现和类外实现

    其实友元模板函数的类内实现就直接实现就好了
    类外实现如下：
        1、定义一个friend 函数，前提是要在函数名的后面跟上一对尖括号
        2、在类外定义这个函数，但是要在friend 类内函数声明之前
        3、在声明之前，也就是 类的实现之前了，所以要在前面先声明有这样一个类的类型；
*/
#include <iostream>

// 3、在声明之前，也就是 类的实现之前了，所以要在前面先声明有这样一个类的类型；
template <typename T1, typename T2>
class Calculator;

// 2、在类外定义这个函数，但是要在friend 类内函数声明之前
template <typename T1, typename T2>
void print(const Calculator<T1, T2> &cal)
{
    std::cout << "t1 = " << cal.t1 << ", t2 = " << cal.t2 << std::endl;
}

template <typename T1, typename T2>
class Calculator
{

    // 下面是友元全局模板函数的类内实现
    // friend void print(const Calculator<T1, T2> &cal)
    // {
    //     std::cout << "t1 = " << cal.t1 << ", t2 = " << cal.t2 << std::endl;
    // }

    // 下面是友元模板函数的类外实现（注意都是全局函数）
    // 1、定义一个friend 函数，前提是要在函数名的后面跟上一对尖括号
    friend void print<>(const Calculator<T1, T2> &);

private:
    T1 t1;
    T2 t2;

public:
    Calculator();
    Calculator(T1, T2);
};

template <typename T1, typename T2>
Calculator<T1, T2>::Calculator()
{
    std::cout << "Calculator 的无参构造函数执行了" << std::endl;
}

template <typename T1, typename T2>
Calculator<T1, T2>::Calculator(T1 t1, T2 t2)
{
    this->t1 = t1;
    this->t2 = t2;
}

int main(int argc, char const *argv[])
{
    Calculator<int, int> cal{20, 30};
    print(cal);
    return 0;
}
